#include "Layer.hpp"
#include "Bits.h"
#include "Rede.h"
#include <iostream>
#include <boost/thread.hpp>
#include <boost/date_time.hpp>
#include "Fisico.hpp"
#include "Enlace.hpp"
#include <qrencode.h>
#include "QrImage.hpp"
#include "Layer.hpp"
#include <vector>
//#include "Fisico.hpp"
#include "Transporte.h"

using namespace ufpb::project::network;

class Teste : public Layer {

	public:

		Teste(void) : Layer(0) {
		
		};
		~Teste() {};

		void newMessageToSend(Bits* msg) {

			std::cout << "Teste - Nova message pra enviar pra baixo ";
                        msg->println();
		}

		void newReceivedMessage(Bits* msg) {

			std::cout << "Teste - Nova message Recebida ";
                        msg->println();
		}
};

class Teste2 : public Layer {

	public:
	
		Teste2(void) : Layer(0) {
		};

		~Teste2() {};

		void newMessageToSend(Bits* msg) {

//			std::cout << "Teste2 - Nova message pra enviar pra baixo ";
//                        msg->println();
                        getUpLayer()->receive(msg);
		}

		void newReceivedMessage(Bits* msg) {

			std::cout << "Teste2 - Nova message Recebida ";
                        msg->println();
		}
};

//void testarTudo() {
//    Transporte *transporte = new Transporte();
//    Transporte *transporte2 = new Transporte();
//    Enlace *enlace = new Enlace(13);
//    Enlace *enlace2 = new Enlace(14);
//    Rede *rede1 = new Rede();
//    map<string, string> mapa;
//    mapa["meuIP"] = "5";
//    mapa["mac"] = "14";
//    mapa["souOGateway"] = "false";
//    mapa["mapa"] = "4-13,5-14";
//
//    Rede *rede2 = new Rede(&mapa);
//
//    Teste *teste = new Teste();
//    Teste *teste2 = new Teste();
//
//    transporte->setDownLayer(rede1);
//    rede1->setDownLayer(enlace);
//    enlace->setDownLayer(teste);
//    rede1->setUpLayer(transporte);
//    enlace->setUpLayer(rede1);
////    teste->setUpLayer(transporte2);
//    teste->setUpLayer(enlace2);
//    transporte2->setDownLayer(rede2);
//    rede2->setDownLayer(enlace2);
//    enlace2->setDownLayer(teste2);
//    enlace2->setUpLayer(rede2);
//    rede2->setUpLayer(transporte2);
//    teste2->setUpLayer(enlace);
//    transporte->setUpLayer(teste);
//    transporte->init();
//    teste->init();
//    enlace->init();
//    rede->init();
//
//    Bits* msg = new Bits(120);
//    int ipDestino = 5;
//    string str = "oi";
//    msg->putInfo(Transporte::IP_OFFSET, Transporte::IP_LENGTH, ipDestino);
//    msg->putInfo(4, 16, 123);
//    transporte->send(msg);
//    while(true){}
//}

void testarFisicoComResto() {
	Transporte *transporte = new Transporte();
	    Enlace *enlace = new Enlace(14);
	    map<string, string> mapa;
	    mapa["meuIP"] = "5";
	    mapa["mac"] = "14";
	    mapa["souOGateway"] = "false";
	    mapa["mapa"] = "4-13,5-14";

	    Rede *rede = new Rede(&mapa);
	    Fisico *fisico = new Fisico();

	    Teste *teste = new Teste();

	    transporte->setDownLayer(rede);
	    rede->setDownLayer(enlace);
	    enlace->setDownLayer(fisico);
	    fisico->setUpLayer(enlace);
	    rede->setUpLayer(transporte);
	    enlace->setUpLayer(rede);
	    transporte->setUpLayer(teste);
	    fisico->init();
	    sleep(3);
	    enlace->init();
	    transporte->init();
	    teste->init();

	    rede->init();


	    Bits* msg = new Bits(120);
	    int ipDestino = 5;
	    string str = "oi";
	    msg->putInfo(Transporte::IP_OFFSET, Transporte::IP_LENGTH, ipDestino);
	    msg->putInfo(4, 16, 123);
//	    transporte->send(msg);
	    while(true){}
}

void testRede() {
    Teste* t = new Teste();
    t->init();
    
    Bits* msgPraBaixo = new Bits(8);
    Bits* msgPraCima = new Bits(16);
    int ipDestino = 5;
    int macDestino = 10;
    int meuIP = 2;
    int payLoad = 10;
    
    msgPraBaixo->putInfo(0,4,ipDestino);
    msgPraBaixo->putInfo(4,4,payLoad);
    
    msgPraCima->putInfo(0,4,macDestino);
    msgPraCima->putInfo(4,4,meuIP);
    msgPraCima->putInfo(8,4,ipDestino);
    msgPraCima->putInfo(12,4,payLoad);
    
    Rede* r = new Rede();
    r->init();
    r->setDownLayer(t);
    r->setUpLayer(t);
    while(true) {
        r->send(msgPraBaixo);
        sleep(2);
        r->receive(msgPraCima);
        sleep(2);
        
    }
}

void printQr(unsigned char* g, int width) {

	for (int i = 0; i < width; i++) {

		for (int j = 0; j < width; j++) {

			if (g[i * width + j] & 0 == 0) {

				printf("%c", ' ');
			} else {

				printf("%c", '.');
			}
		}
		putchar('\n');
	}
}

//int main(int argc, char* argv[]) {
int main(int argc, char* argv[]) {

testarFisicoComResto();

//	char* string = "11223344556677889900";
//	QRcode* code = QRcode_encodeString8bit(string, 2, QR_ECLEVEL_L );
//
//	printf("%d - %p\n", errno, code);
//	printf("width: %d\n", code->width);
//	printf("version: %d\n", code->version);
//	printf("%d\n",code->data[0] & 0);
//
//	printQr(code->data, code->width);
//
//	QrImage* qr = new QrImage(code->data, code->width);
//
//
//	Imagem* teste = qr->getImage()->resize(10);
//
//	Imagem* resultado = new Imagem(teste->width()+100, teste->height()+100,1);
//	resultado->setAllPixels(255);
//	resultado->add(teste, 50, 50);
//
//	cvNamedWindow( "result", CV_WINDOW_AUTOSIZE );
//	cvShowImage( "result",resultado->getIplImage() );
//	cvWaitKey( 100 );

	//const char* tostr = std::string("berg55igor").c_str();
	//int len = strlen(tostr);




	/*Fisico *fisico = new Fisico();
	//Enlace * enlace = new Enlace();

	//fisico->setUpLayer(enlace);
	//enlace->setDownLayer(fisico);

	Bits* b = new Bits(16);
	Bits* b1 = new Bits(16);

	b->set(0, 0);
	b->set(1, 0);
	b->set(2, 1);
	b->set(3, 1);
	b->set(4, 0);
	b->set(5, 0);
	b->set(6, 1);
	b->set(7, 0);

	b->set(0+8, 0);
	b->set(1+8, 1);
	b->set(2+8, 0);
	b->set(3+8, 0);
	b->set(4+8, 0);
	b->set(5+8, 0);
	b->set(6+8, 1);
	b->set(7+8, 0);

	b1->set(0, 1);
	b1->set(1, 0);
	b1->set(2, 1);
	b1->set(3, 1);
	b1->set(4, 0);
	b1->set(5, 1);
	b1->set(6, 0);
	b1->set(7, 0);

	b1->set(0+8, 1);
	b1->set(1+8, 1);
	b1->set(2+8, 0);
	b1->set(3+8, 0);
	b1->set(4+8, 1);
	b1->set(5+8, 0);
	b1->set(6+8, 0);
	b1->set(7+8, 1);
	cout<<"oi";

	//enlace->init();
	fisico->init();

//	while (true) {
		//enlace->getDownLayer()->send(b);
//		enlace->getDownLayer()->send(b);
//		enlace->getDownLayer()->send(b);

	char* tostr = "1234587890";
	int l = strlen(tostr);
	Bits* bs = new Bits(l * 8);
	for (int i = 0; i < l; i++) {

			int mask = 0x80;
			bs->set(i*8, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+1, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+2, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+3, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+4, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+5, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+6, tostr[i] & mask);
			mask = mask >> 1;
			bs->set(i*8+7, tostr[i] & mask);

		}

	fisico->send(new Bits("testando.."));
//	bs->println();

	for(int i = 0; i < 6; ++i){

		fisico->send(b);

		cout<<"oi";

		fisico->send(b1);

		cout<<"oi";

		//fisico->send(b);
	}


//		enlace->getDownLayer()->send(b);
//	fisico->newMessageToSend(b);
//	}
//    testRede();

	while(true);
*/
}
